<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>

	<body>
		享元模式的主要思想是细粒度对象的共享和复用，因此对之前的驾考例子，我们可以继续改进一下：<br> 
		如果某考生正在使用一辆驾考车，那么这辆驾考车的状态就是被占用，其他考生只能选择剩下未被占用状态的驾考车；

		<br> 如果某考生对驾考车的使用完毕，那么将驾考车开回考点，驾考车的状态改为未被占用，供给其他考生使用；
		<br> 如果所有驾考车都被占用，那么其他考生只能等待正在使用驾考车的考生使用完毕，直到有驾考车的状态变为未被占用；
		<br> 组织单位可以根据考生数量多准备几辆驾考车，比如手动档考生比较多，那么手动档驾考车就应该比自动档驾考车多准备几辆；
		<br>
		
		
	</body>
	<script>
		let examCarNum = 0 // 驾考车总数

		/* 驾考车对象 */
		class ExamCar {
			constructor(carType) {
				examCarNum++
				this.carId = examCarNum
				this.carType = carType ? '手动档' : '自动档'
				this.usingState = false // 是否正在使用
			}

			/* 在本车上考试 */
			examine(candidateId) {
				return new Promise((resolve => {
					this.usingState = true
					console.log(`考生- ${ candidateId } 开始在${ this.carType }驾考车- ${ this.carId } 上考试`)
					setTimeout(() => {
						this.usingState = false
						console.log(`%c考生- ${ candidateId } 在${ this.carType }驾考车- ${ this.carId } 上考试完毕`, 'color:#f40')
						resolve() // 0~2秒后考试完毕
					}, Math.random() * 2000)
				}))
			}
		}

		/* 手动档汽车对象池 */
		ManualExamCarPool = {
			_pool: [], // 驾考车对象池
			_candidateQueue: [], // 考生队列

			/* 注册考生 ID 列表 */
			registCandidates(candidateList) {
				candidateList.forEach(candidateId => this.registCandidate(candidateId))
			},

			/* 注册手动档考生 */
			registCandidate(candidateId) {
				const examCar = this.getManualExamCar() // 找一个未被占用的手动档驾考车
				if(examCar) {
					examCar.examine(candidateId) // 开始考试，考完了让队列中的下一个考生开始考试
						.then(() => {
							const nextCandidateId = this._candidateQueue.length && this._candidateQueue.shift()
							nextCandidateId && this.registCandidate(nextCandidateId)
						})
				} else this._candidateQueue.push(candidateId)
			},

			/* 注册手动档车 */
			initManualExamCar(manualExamCarNum) {
				for(let i = 1; i <= manualExamCarNum; i++) {
					this._pool.push(new ExamCar(true))
				}
			},

			/* 获取状态为未被占用的手动档车 */
			getManualExamCar() {
				return this._pool.find(car => !car.usingState)
			}
		}

		ManualExamCarPool.initManualExamCar(3) // 一共有3个驾考车
		ManualExamCarPool.registCandidates([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) // 10个考生来考试
	</script>

</html>